﻿/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Reflection;
using System.Diagnostics;
using System.Data.SQLite;
using System.Data.Common;

namespace IvyOrm.Test
{
    [TestClass]
    [DeploymentItem("x86")] //SQLite Files
    public class RecordQueryExtensionTest
    {
        public class SimpleClass
        {
            public string ColumnA;
            public string ColumnB { get; set; }
        }
        public struct SimpleStruct
        {
            public string ColumnA;
            public string ColumnB { get; set; }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordQuery_InvalidArgument()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                AssertB.ThrowsException<ArgumentException>(() => RecordQueryExtension.RecordQuery<SimpleClass>((DbConnection)null, ""));
                AssertB.ThrowsException<ArgumentException>(() => RecordQueryExtension.RecordQuery<int>(connection, "")); //Primitive Type
                AssertB.ThrowsException<ArgumentException>(() => RecordQueryExtension.RecordQuery<TypeCode>(connection, "")); //enum
            }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordQuery_InvalidArgument_Transaction()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                using (var transaction = connection.BeginTransaction())
                {
                    AssertB.ThrowsException<ArgumentException>(() => RecordQueryExtension.RecordQuery<SimpleClass>((DbTransaction)null, ""));
                    AssertB.ThrowsException<ArgumentException>(() => RecordQueryExtension.RecordQuery<SimpleClass>(new BadDbTransaction(), ""));
                    AssertB.ThrowsException<ArgumentException>(() => RecordQueryExtension.RecordQuery<int>(transaction, "")); //Primitive Type
                    AssertB.ThrowsException<ArgumentException>(() => RecordQueryExtension.RecordQuery<TypeCode>(transaction, "")); //enum
                    
                }
            }
        }


        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordQuery_SimpleClass()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table MultiColumnTable (ColumnA TEXT, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row1", "alpha");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row2", "beta");

                {
                    var results = connection.RecordQuery<SimpleClass>("select ColumnA, ColumnB from MultiColumnTable order by ColumnA");
                    Assert.IsTrue(results[0].ColumnA == "row1");
                    Assert.IsTrue(results[0].ColumnB == "alpha");
                    Assert.IsTrue(results[1].ColumnA == "row2");
                    Assert.IsTrue(results[1].ColumnB == "beta");
                }

                {
                    var results = connection.RecordQuery<SimpleClass>(new IvyOrmOptions(), "select ColumnA, ColumnB from MultiColumnTable order by ColumnA");
                    Assert.IsTrue(results[0].ColumnA == "row1");
                    Assert.IsTrue(results[0].ColumnB == "alpha");
                    Assert.IsTrue(results[1].ColumnA == "row2");
                    Assert.IsTrue(results[1].ColumnB == "beta");
                }

            }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordQuery_SimpleClass_Transaction()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table MultiColumnTable (ColumnA TEXT, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row1", "alpha");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row2", "beta");

                using (var transaction = connection.BeginTransaction())
                {
                    {
                        var results = transaction.RecordQuery<SimpleClass>("select ColumnA, ColumnB from MultiColumnTable order by ColumnA");
                        Assert.IsTrue(results[0].ColumnA == "row1");
                        Assert.IsTrue(results[0].ColumnB == "alpha");
                        Assert.IsTrue(results[1].ColumnA == "row2");
                        Assert.IsTrue(results[1].ColumnB == "beta");
                    }

                    {
                        var results = transaction.RecordQuery<SimpleClass>(new IvyOrmOptions(), "select ColumnA, ColumnB from MultiColumnTable order by ColumnA");
                        Assert.IsTrue(results[0].ColumnA == "row1");
                        Assert.IsTrue(results[0].ColumnB == "alpha");
                        Assert.IsTrue(results[1].ColumnA == "row2");
                        Assert.IsTrue(results[1].ColumnB == "beta");
                    }

                }
            }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordQuery_SimpleStruct()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table MultiColumnTable (ColumnA TEXT, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row1", "alpha");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row2", "beta");

                var results = connection.RecordQuery<SimpleStruct>("select ColumnA, ColumnB from MultiColumnTable order by ColumnA");

                Assert.IsTrue(results[0].ColumnA == "row1");
                Assert.IsTrue(results[0].ColumnB == "alpha");
                Assert.IsTrue(results[1].ColumnA == "row2");
                Assert.IsTrue(results[1].ColumnB == "beta");
            }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordQuery_ExtraFields()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table MultiColumnTable (ColumnA TEXT, ColumnB TEXT, ColumnC TEXT)");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row1", "alpha");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row2", "beta");

                var results = connection.RecordQuery<SimpleStruct>("select ColumnA, ColumnB, ColumnC from MultiColumnTable order by ColumnA");

                Assert.IsTrue(results.Length == 2);
                var options = new IvyOrmOptions { RecordQueryOptions = RecordQueryOptions.ThrowErrorOnExtraFields };
                AssertB.ThrowsException<IvyOrmException>(() =>
                    connection.RecordQuery<SimpleStruct>(options, "select ColumnA, ColumnB, ColumnC from MultiColumnTable order by ColumnA")
                    );
            }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordQuery_MissingFields()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table MultiColumnTable (ColumnA TEXT, ColumnB TEXT, ColumnC TEXT)");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row1", "alpha");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row2", "beta");

                var results = connection.RecordQuery<SimpleStruct>("select ColumnA from MultiColumnTable order by ColumnA");

                Assert.IsTrue(results.Length == 2);

                var options = new IvyOrmOptions { RecordQueryOptions = RecordQueryOptions.ThrowErrorOnMissingFields };
                AssertB.ThrowsException<IvyOrmException>(() =>
                    connection.RecordQuery<SimpleStruct>(options, "select ColumnA from MultiColumnTable order by ColumnA")
                    );

                AssertB.ThrowsException<IvyOrmException>(() =>
                    connection.RecordQuery<SimpleStruct>(options, "select ColumnA, ColumnC from MultiColumnTable order by ColumnA")
                    );
            }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordQuery_SingleResult()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table MultiColumnTable (ColumnA TEXT, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row1", "alpha");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row2", "beta");

                var options = new IvyOrmOptions { RecordQueryOptions = RecordQueryOptions.SingleRow };
                var results = connection.RecordQuery<SimpleStruct>(options, "select ColumnA from MultiColumnTable order by ColumnA");

                Assert.IsTrue(results.Length == 1);
            }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordQuery_CustomFactory()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table MultiColumnTable (ColumnA TEXT, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row1", "alpha");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row2", "beta");

                var options = new IvyOrmOptions {  ValueConverterFactory = new BangFactory() };
                var results = connection.RecordQuery<SimpleStruct>(options, "select ColumnA, ColumnB from MultiColumnTable order by ColumnA");

                Assert.AreEqual("row1!", results[0].ColumnA);
                Assert.AreEqual("alpha!", results[0].ColumnB);
                Assert.AreEqual("row2!", results[1].ColumnA);
                Assert.AreEqual("beta!", results[1].ColumnB);
            }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordQuery_NullValue()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table MultiColumnTable (ColumnA TEXT, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row1", null);

                var results = connection.RecordQuery<SimpleClass>("select * from MultiColumnTable");

                Assert.AreEqual(results[0].ColumnB, null);
            }
        }

        [Table(TableOptions.ColumnsOptIn)]
        public class OptInClass
        {
            [Column]
            public string ColumnA { get; set; }
            public string ColumnB { get; set; }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordQuery_OptIn()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table MultiColumnTable (ColumnA TEXT, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row1", "alpha");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row2", "beta");

                var results = connection.RecordQuery<OptInClass>("select ColumnA, ColumnB from MultiColumnTable order by ColumnA");

                Assert.AreEqual(null, results[0].ColumnB);
                Assert.AreEqual(null, results[1].ColumnB);
            }
        }

        [Table(TableOptions.ColumnsOptOut)]
        public class OptOutClass
        {
            [ExcludeColumn]
            public string ColumnA { get; set; }
            public string ColumnB { get; set; }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordQuery_OptOut()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table MultiColumnTable (ColumnA TEXT, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row1", "alpha");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row2", "beta");

                var results = connection.RecordQuery<OptOutClass>("select ColumnA, ColumnB from MultiColumnTable order by ColumnA");

                Assert.AreEqual(null, results[0].ColumnA);
                Assert.AreEqual(null, results[1].ColumnA);
            }
        }

        [Table("MultiColumnTable")]
        class ColumnNameMismatch
        {
            [Column("ColumnA")]
            public string AlphaColumn { get; set; }
            [Column("ColumnB")]
            public string BetaColumn { get; set; }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordQuery_ColumnNameMismatch()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table MultiColumnTable (ColumnA TEXT, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row1", "alpha");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row2", "beta");

                var results = connection.RecordQuery<ColumnNameMismatch>("select ColumnA, ColumnB from MultiColumnTable order by ColumnA");

                Assert.AreEqual("row1", results[0].AlphaColumn);
                Assert.AreEqual("alpha", results[0].BetaColumn);

                Assert.AreEqual("row2", results[1].AlphaColumn);
                Assert.AreEqual("beta", results[1].BetaColumn);
            }
        }

        class CaseMismatch
        {
            public string COLUMNA { get; set; }
            public string COLUMNB { get; set; }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordQuery_CaseMismatch()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table MultiColumnTable (ColumnA TEXT, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row1", "alpha");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row2", "beta");

                var results = connection.RecordQuery<CaseMismatch>("select ColumnA, ColumnB from MultiColumnTable order by ColumnA");

                Assert.AreEqual("row1", results[0].COLUMNA);
                Assert.AreEqual("alpha", results[0].COLUMNB);

                Assert.AreEqual("row2", results[1].COLUMNA);
                Assert.AreEqual("beta", results[1].COLUMNB);
            }
        }

        class BangFactory : ValueConverterFactory
        {
            public override Converter<object, object> GetConverter(Type sourceType, Type destinationType)
            {
                return (v) => v.ToString() + "!";
            }
        }

        class CustomFactoryOnSingleColumn
        {
            public string ColumnA { get; set; }
            [Column(null, null, typeof(BangFactory))]
            public string ColumnB { get; set; }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordQuery_CustomFactoryOnSingleColumn()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table MultiColumnTable (ColumnA TEXT, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row1", "alpha");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row2", "beta");

                var results = connection.RecordQuery<CustomFactoryOnSingleColumn>("select ColumnA, ColumnB from MultiColumnTable order by ColumnA");

                Assert.AreEqual("row1", results[0].ColumnA);
                Assert.AreEqual("alpha!", results[0].ColumnB);

                Assert.AreEqual("row2", results[1].ColumnA);
                Assert.AreEqual("beta!", results[1].ColumnB);
            }
        }


        class InvalidCustomFactoryOnSingleColumn
        {
            public string ColumnA { get; set; }
            [Column(null, null, typeof(string))]
            public string ColumnB { get; set; }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordQuery_InvalidCustomFactoryOnSingleColumn()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table MultiColumnTable (ColumnA TEXT, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row1", "alpha");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row2", "beta");

                AssertB.ThrowsException<InvalidOperationException>(() =>
                    connection.RecordQuery<InvalidCustomFactoryOnSingleColumn>("select ColumnA, ColumnB from MultiColumnTable order by ColumnA"));
            }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordSingle_Simple()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table MultiColumnTable (ColumnA TEXT, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row1", "alpha");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row2", "beta");

                {
                    var results = connection.RecordSingle<SimpleClass>("select ColumnA, ColumnB from MultiColumnTable order by ColumnA");
                    Assert.IsTrue(results.ColumnA == "row1");
                    Assert.IsTrue(results.ColumnB == "alpha");
                }

                {
                    var results = connection.RecordSingle<SimpleClass>((IvyOrmOptions)null, "select ColumnA, ColumnB from MultiColumnTable order by ColumnA");
                    Assert.IsTrue(results.ColumnA == "row1");
                    Assert.IsTrue(results.ColumnB == "alpha");
                }

                AssertB.ThrowsException<IvyOrmException>(() => connection.RecordSingle<SimpleClass>("select ColumnA, ColumnB from MultiColumnTable where ColumnA='none'"));
            }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordSingle_Simple_Transaction()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table MultiColumnTable (ColumnA TEXT, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row1", "alpha");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row2", "beta");

                using (var transaction = connection.BeginTransaction())
                {

                    {
                        var results = transaction.RecordSingle<SimpleClass>("select ColumnA, ColumnB from MultiColumnTable order by ColumnA");
                        Assert.IsTrue(results.ColumnA == "row1");
                        Assert.IsTrue(results.ColumnB == "alpha");
                    }

                    {
                        var results = transaction.RecordSingle<SimpleClass>(new IvyOrmOptions(), "select ColumnA, ColumnB from MultiColumnTable order by ColumnA");
                        Assert.IsTrue(results.ColumnA == "row1");
                        Assert.IsTrue(results.ColumnB == "alpha");
                    }

                    AssertB.ThrowsException<IvyOrmException>(() => transaction.RecordSingle<SimpleClass>("select ColumnA, ColumnB from MultiColumnTable where ColumnA='none'"));
                }
            }
        }

        [TestMethod]
        [TestCategory("No Database")]
        public void RecordSingle_InvalidArguments()
        {
            AssertB.ThrowsException<ArgumentNullException>(() => RecordQueryExtension.RecordSingle<SimpleClass>((DbConnection)null, "select"));
            AssertB.ThrowsException<ArgumentNullException>(() => RecordQueryExtension.RecordSingle<SimpleClass>((DbTransaction)null, "select"));
            AssertB.ThrowsException<ArgumentException>(() => RecordQueryExtension.RecordSingle<SimpleClass>(new BadDbTransaction(), "select"));
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordSingleOrDefault_Simple()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table MultiColumnTable (ColumnA TEXT, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row1", "alpha");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row2", "beta");

                {
                    var results = connection.RecordSingleOrDefault<SimpleClass>("select ColumnA, ColumnB from MultiColumnTable order by ColumnA");
                    Assert.IsTrue(results.ColumnA == "row1");
                    Assert.IsTrue(results.ColumnB == "alpha");
                }

                {
                    var results = connection.RecordSingleOrDefault<SimpleClass>(new IvyOrmOptions(), "select ColumnA, ColumnB from MultiColumnTable order by ColumnA");
                    Assert.IsTrue(results.ColumnA == "row1");
                    Assert.IsTrue(results.ColumnB == "alpha");
                }

                {
                    var results = connection.RecordSingleOrDefault<SimpleClass>((IvyOrmOptions)null, "select ColumnA, ColumnB from MultiColumnTable order by ColumnA");
                    Assert.IsTrue(results.ColumnA == "row1");
                    Assert.IsTrue(results.ColumnB == "alpha");
                }

            }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordSingleOrDefault_Simple_Transaction()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table MultiColumnTable (ColumnA TEXT, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row1", "alpha");
                connection.ExecuteNonQuery("insert into MultiColumnTable (ColumnA, ColumnB) values (@0, @1)", "row2", "beta");
                using (var transaction = connection.BeginTransaction())
                {
                    {
                        var results = transaction.RecordSingleOrDefault<SimpleClass>("select ColumnA, ColumnB from MultiColumnTable order by ColumnA");
                        Assert.IsTrue(results.ColumnA == "row1");
                        Assert.IsTrue(results.ColumnB == "alpha");
                    }

                    {
                        var results = transaction.RecordSingleOrDefault<SimpleClass>(new IvyOrmOptions(), "select ColumnA, ColumnB from MultiColumnTable order by ColumnA");
                        Assert.IsTrue(results.ColumnA == "row1");
                        Assert.IsTrue(results.ColumnB == "alpha");
                    }

                    { //RecordQueryOptions.SingleRow should have the same results
                        var results = transaction.RecordSingleOrDefault<SimpleClass>(new IvyOrmOptions { RecordQueryOptions = RecordQueryOptions.SingleRow }, "select ColumnA, ColumnB from MultiColumnTable order by ColumnA");
                        Assert.IsTrue(results.ColumnA == "row1");
                        Assert.IsTrue(results.ColumnB == "alpha");
                    }


                }
            }
        }

        [TestMethod]
        [TestCategory("No Database")]
        public void RecordSingleOrDefault_InvalidArguments()
        {
            AssertB.ThrowsException<ArgumentNullException>(() => RecordQueryExtension.RecordSingleOrDefault<SimpleClass>((DbConnection)null, "select"));
            AssertB.ThrowsException<ArgumentNullException>(() => RecordQueryExtension.RecordSingleOrDefault<SimpleClass>((DbTransaction)null, "select"));
            AssertB.ThrowsException<ArgumentException>(() => RecordQueryExtension.RecordSingleOrDefault<SimpleClass>(new BadDbTransaction(), "select"));
        }
    }
}
